package org.chen.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shardingsphere.api.hint.HintManager;
import org.chen.common.constants.Constants;
import org.chen.common.exception.ExceptionCodeEnum;
import org.chen.common.exception.FlyingException;
import org.chen.common.model.DailyStats;
import org.chen.common.model.travel.StoreTravelOrder;
import org.chen.common.model.travel.StoreTravelOrderInfo;
import org.chen.common.page.CommonPage;
import org.chen.common.request.PageParamRequest;
import org.chen.common.request.RejectRefundRequest;
import org.chen.common.response.OrderTravelDetailResponse;
import org.chen.common.response.OrderTravelInfoResponse;
import org.chen.common.utils.DateUtil;
import org.chen.common.utils.RedisUtil;
import org.chen.common.vo.MyRecord;
import org.chen.mapper.DailyStatsMapper;
import org.chen.mapper.StoreTravelOrderMapper;
import org.chen.service.AsyncTaskService;
import org.chen.service.DailyStatsService;
import org.chen.service.StoreTravelOrderService;
import org.chen.service.UserService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static org.chen.common.constants.Constants.TOKEN_EXPRESS_MINUTES_1;

@Slf4j
@Service
public class DailyStatsServiceImpl extends ServiceImpl<DailyStatsMapper , DailyStats> implements DailyStatsService {
    @Autowired
    private DailyStatsMapper dailyStatsMapper;

    @Autowired
    private StoreTravelOrderService storeTravelOrderService;

    @Autowired
    private RedissonClient redisson;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private AsyncTaskService asyncTaskService;

    @Override
    public DailyStats findByStatDateForUpdate(Date statDate) {
        return dailyStatsMapper.selectOne(new QueryWrapper<DailyStats>().eq("stat_date",statDate).last("FOR UPDATE"));
    }

    @Override
    public void updateByIdWithVersion(DailyStats dailyStats) {
        LambdaUpdateWrapper<DailyStats> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(DailyStats::getId, dailyStats.getId())
                .set(DailyStats::getOrderCount, dailyStats.getOrderCount())
                .set(DailyStats::getTotalAmount, dailyStats.getTotalAmount())
                .set(DailyStats::getRefundAmount, dailyStats.getRefundAmount())
                .set(DailyStats::getUpdatedAt, dailyStats.getUpdatedAt());
        dailyStatsMapper.update(null, updateWrapper);
    }

    @Override
    public DailyStats getDailyStats() {
        Date today = DateUtils.truncate(new Date(), Calendar.DATE);
        return dailyStatsMapper.selectOne(new QueryWrapper<DailyStats>().eq("stat_date", today));
    }

    @Override
    public CommonPage<OrderTravelDetailResponse> getRefundOrders(Integer status, String orderId, PageParamRequest pageRequest) {
        Page<StoreTravelOrder> userOrderRefundList;
        if (orderId != null && !orderId.isEmpty()){
            userOrderRefundList = storeTravelOrderService.getUserOrderRefundByOderId(orderId, pageRequest);
        }else {
            userOrderRefundList = storeTravelOrderService.getUserOrderRefundList(null, status, pageRequest);
        }
        CommonPage<StoreTravelOrder> storeOrderCommonPage = CommonPage.page(userOrderRefundList);
        List<OrderTravelDetailResponse> responseList = CollUtil.newArrayList();
        for (StoreTravelOrder storeOrder : userOrderRefundList.getRecords()) {
            OrderTravelDetailResponse infoResponse = new OrderTravelDetailResponse();
            BeanUtils.copyProperties(storeOrder, infoResponse);
            // 订单状态
            infoResponse.setPayId(storeOrder.getPayId());
            infoResponse.setRefundReasonWap(storeOrder.getRefundReasonWap());
            infoResponse.setRefundReasonWapExplain(storeOrder.getRefundReasonWapExplain());
            infoResponse.setOrderStatus(getH5TravelOrderRefundStatus(storeOrder));
            MyRecord orderStatusVo = getOrderTravelRefundStatusVo(storeOrder);
            infoResponse.setOrderStatusMsg(orderStatusVo.getStr("msg"));
            infoResponse.setId(storeOrder.getId().toString());
            responseList.add(infoResponse);
        }
        CommonPage<OrderTravelDetailResponse> detailPage = CommonPage.restPage(responseList);
        BeanUtils.copyProperties(storeOrderCommonPage, detailPage, "list");
        return detailPage;
    }

    @Override
    public CommonPage<OrderTravelDetailResponse> getOrders(Integer type, String orderId, PageParamRequest pageRequest) {
        Page<StoreTravelOrder> userOrderList;
        if (orderId != null && !orderId.isEmpty()){
            userOrderList = storeTravelOrderService.getUserOrderByOderId(orderId, pageRequest);
        }else {
            userOrderList = storeTravelOrderService.getUserOrderList(null, type, pageRequest);
        }

        CommonPage<StoreTravelOrder> storeOrderCommonPage = CommonPage.page(userOrderList);
        List<OrderTravelDetailResponse> responseList = CollUtil.newArrayList();
        for (StoreTravelOrder storeOrder : userOrderList.getRecords()) {
            OrderTravelDetailResponse infoResponse = new OrderTravelDetailResponse();
            BeanUtils.copyProperties(storeOrder, infoResponse);
            // 订单状态
            if (storeOrder.getPaid()){
                infoResponse.setPayId(storeOrder.getPayId());
            }
            infoResponse.setId(storeOrder.getId().toString());
            infoResponse.setOrderStatus(getH5TravelOrderStatus(storeOrder));
            MyRecord orderStatusVo = getOrderTravelStatusVo(storeOrder);
            infoResponse.setOrderStatusMsg(orderStatusVo.getStr("msg"));
            responseList.add(infoResponse);
        }
        CommonPage<OrderTravelDetailResponse> detailPage = CommonPage.restPage(responseList);
        BeanUtils.copyProperties(storeOrderCommonPage, detailPage, "list");
        return detailPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean approveRefund(Long id, String orderId) {
        String lockKey = "refund_lock:" + id + orderId;
        RLock lock = redisson.getLock(lockKey);
        try {
            if (!lock.tryLock(5, TimeUnit.SECONDS)) {
                throw new FlyingException(ExceptionCodeEnum.SYSTEM_BUSY, "系统繁忙，请稍后重试");
            }

            // 幂等性检查
            if (redisUtil.exists("refund_processed:" + id + orderId)) {
                throw new FlyingException(ExceptionCodeEnum.REFUND_ALREADY_PROCESSED, "退款申请已处理");
            }

            StoreTravelOrder existStoreOrder = storeTravelOrderService.getByOrderIdWithLock(orderId);
            if (existStoreOrder == null) {
                throw new FlyingException(ExceptionCodeEnum.THE_PAYMENT_SLIP_DOES_NOT_EXIST, "支付订单不存在");
            }

            validateRefundRequest(existStoreOrder);

            // 更新订单状态为退款申请中
            existStoreOrder.setRefundStatus(3);
            existStoreOrder.setRefundReasonTime(DateUtil.nowDateTime());
            existStoreOrder.setRemark("审核通过");
            existStoreOrder.setRefundPrice(BigDecimal.ZERO);

            boolean updateResult = storeTravelOrderService.updateById(existStoreOrder);
            if (!updateResult) {
                throw new FlyingException(ExceptionCodeEnum.ORDER_UPDATE_FAILED, "订单状态更新失败");
            }

            // 标记退款申请已处理
            redisUtil.set("refund_processed:" + id + orderId, "1", TOKEN_EXPRESS_MINUTES_1, TimeUnit.MINUTES);

            // 异步处理退款
            asyncTaskService.agreeRefund(existStoreOrder);

            return true;
        }catch (Exception e) {
            log.error("Refund application failed", e);
            redisTemplate.delete("order_processed:" + id + orderId);
            throw new FlyingException(ExceptionCodeEnum.THE_REFUND_REQUEST_FAILED, "申请退款失败: " + e.getMessage());
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


    private void validateRefundRequest(StoreTravelOrder order) {
        if (order.getRefundStatus() == 2) {
            throw new FlyingException(ExceptionCodeEnum.THE_ORDER_HAS_BEEN_REFUNDED, "订单已退款");
        }
        if (order.getRefundStatus() == 3) {
            throw new FlyingException(ExceptionCodeEnum.THE_ORDER_IS_BEING_REFUNDED, "订单退款中");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean rejectRefund(Long id, String orderId, RejectRefundRequest request) {
        StoreTravelOrder existStoreOrder = storeTravelOrderService.getByOrderIdWithLock(orderId);
        if (existStoreOrder == null) {
            throw new FlyingException(ExceptionCodeEnum.THE_PAYMENT_SLIP_DOES_NOT_EXIST, "支付订单不存在");
        }
        // 更新订单状态为退款申请中
        existStoreOrder.setRefundStatus(4);
        existStoreOrder.setRefundReasonTime(DateUtil.nowDateTime());
        existStoreOrder.setRefundReason(request.getReason());
        existStoreOrder.setRefundPrice(BigDecimal.ZERO);

        boolean updateResult = storeTravelOrderService.updateById(existStoreOrder);
        redisTemplate.delete("refund_processed:" + orderId);
        if (!updateResult) {
            throw new FlyingException(ExceptionCodeEnum.ORDER_UPDATE_FAILED, "订单状态更新失败");
        }
        return true;
    }

    /**
     * 获取H5订单状态（旅游）
     *
     * @param storeOrder 订单对象
     */
    private String getH5TravelOrderRefundStatus(StoreTravelOrder storeOrder) {
        if (storeOrder.getRefundStatus().equals(1)) {
            return "待审核";
        }
        if (storeOrder.getRefundStatus().equals(2)) {
            return "已退款";
        }
        if (storeOrder.getRefundStatus().equals(3)) {
            return "退款中";
        }
        if (storeOrder.getRefundStatus().equals(4)) {
            return "退款失败";
        }
        return "";
    }

    private String getH5TravelOrderStatus(StoreTravelOrder storeOrder) {
        if (!storeOrder.getPaid()) {
            if (storeOrder.getStatus().equals(3)) {
                return "已取消";
            }
            return "待支付";
        }
        if (storeOrder.getRefundStatus().equals(1)) {
            return "申请退款中";
        }
        if (storeOrder.getRefundStatus().equals(2)) {
            return "已退款";
        }
        if (storeOrder.getRefundStatus().equals(3)) {
            return "退款中";
        }
        if (storeOrder.getRefundStatus().equals(4)) {
            return "退款失败";
        }
        if (storeOrder.getStatus().equals(1)) {
            return "待使用";
        }
        if (storeOrder.getStatus().equals(2)) {
            return "已完成";
        }
        if (storeOrder.getStatus().equals(3)) {
            return "已取消";
        }
        return "";
    }

    /**
     * 获取订单状态相关信息(旅游)
     *
     * @return MyRecord
     */
    private MyRecord getOrderTravelRefundStatusVo(StoreTravelOrder storeOrder) {
        MyRecord record = new MyRecord();
        if (storeOrder.getRefundStatus() == 1) {
            record.set("type", -1);
            record.set("title", "申请退款中");
            record.set("msg", "审核中,请耐心等待");
        } else if (storeOrder.getRefundStatus() == 2) {
            record.set("type", -2);
            record.set("title", "已退款");
            record.set("msg", "已为您退款,感谢您的支持");
        } else if (storeOrder.getRefundStatus() == 3) {
            record.set("type", -3);
            record.set("title", "退款中");
            record.set("msg", "正在为您退款,感谢您的支持");
        }else if (storeOrder.getRefundStatus() == 4) {
            record.set("type", -4);
            record.set("title", "退款失败");
            record.set("msg", "如有疑问请联系客服,感谢您的支持");
        }
        return record;
    }

    private MyRecord getOrderTravelStatusVo(StoreTravelOrder storeOrder) {
        MyRecord record = new MyRecord();
        if (!storeOrder.getPaid()) {
            if (storeOrder.getStatus().equals(3)) {
                record.set("type", 0);
                record.set("title", "已取消");
                record.set("msg", "已取消");
            }else {
                record.set("type", 0);
                record.set("title", "未支付");
                record.set("msg", "订单未支付");
            }
        } else if (storeOrder.getRefundStatus() == 1) {
            record.set("type", -1);
            record.set("title", "申请退款中");
            record.set("msg", "审核中,请耐心等待");
        } else if (storeOrder.getRefundStatus() == 2) {
            record.set("type", -2);
            record.set("title", "已退款");
            record.set("msg", "已为您退款,感谢您的支持");
        } else if (storeOrder.getRefundStatus() == 3) {
            record.set("type", -3);
            record.set("title", "退款中");
            record.set("msg", "正在为您退款,感谢您的支持");
        }else if (storeOrder.getRefundStatus() == 4) {
            record.set("type", -4);
            record.set("title", "退款失败");
            record.set("msg", "如有疑问请联系客服,感谢您的支持");
        } else if (storeOrder.getStatus() == 1) {
            record.set("type", 0);
            record.set("title", "未使用");
            record.set("msg", "我们会主动联系你,请耐心等待");
        } else if (storeOrder.getStatus() == 2) {
            record.set("type", 1);
            record.set("title", "已使用，待评价");
            record.set("msg", "已使用,快去评价一下吧");
        } else if (storeOrder.getStatus() == 3) {
            record.set("type", 2);
            record.set("title", "交易完成");
            record.set("msg", "交易完成,感谢您的支持");
        }
        return record;
    }
}
